更多 Android Framework 相关教程:https://yuandaimaahao.gitee.io/androidframeworktutorialpages/
本文基于 AOSP android-10.0.0_r41 版本讲解
这一节,我们主要分析在 Android 平台上一个新的进程是如何启动的。
# 1. 整体流程
Android 平台中启动一个新进程过程如下:
- Zygote 开启 socket 服务,然后调用
runSelectLoop
方法进入无限循环中等待 socket 消息 - SystemServer 中的 AMS 向 Zygote 发送一个启动新进程的 Socket 消息
- Zygote 收到启动新进程的 socket 消息后,fork 新进程并执行新进程的 main 函数
# 2. Zygote 服务端的准备过程
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
@UnsupportedAppUsage
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;
// ......
Runnable caller;
try {
// 初始化 ZygoteServer
zygoteServer = new ZygoteServer(isPrimaryZygote);
// ......
// 进入无线循环中等待消息
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}
// 执行新进程的 main 函数
if (caller != null) {
caller.run();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
省略了非相关代码,相关的核心流程主要三步:
zygoteServer = new ZygoteServer(isPrimaryZygote)
初始化 ZygoteServerrunSelectLoop
进入无线循环中等待 socket 消息- 在
runSelectLoop
方法内部的无线循环中会收到 socket 消息,然后 fork 新的进程,对于子进程,会将进程的main
函数包装成一个 Runnable,然后返回。返回后 Runnable 保存到 caller 中,然后调用caller.run()
执行新进程的 main函数
接下里我们通过源码来分析整个流程的细节
# 2.1 ZygoteServer 初始化过程分析**
// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
// 初始化 socket fd
// 传入的 isPrimaryZygote 是 true
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
// PRIMARY_SOCKET_NAME = "zygote";
// createManagedSocketFromInitSocket 函数会从环境变量中获取到 zygote socket
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
// usap 启动相关,一种新的启动新进程的方式,默认情况下没有使用,暂时不管
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
// ......
}
// .....
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ZygoteServer 的构造函数中,会调用 createManagedSocketFromInitSocket
从环境变量中获取到 zygote socket fd。然后把这个 fd 包装程一个 LocalServerSocket 保存在 mZygoteSocket 中。
zygote fd 实际是定义在 rc 文件中:
# system/core/rootdir/init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
# socket 定义在这里
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rc 中定义了 zygote socket,我们才可以从环境变量中获取到 zygote socket 的 fd。这里如果不清楚可以先看看前面的 Android 中的 Unix Domain Socket 使用解析
接下来我们来看看 createManagedSocketFromInitSocket 的具体实现:
//从环境变量中获取到 zygote socket
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
// 从环境遍历中获取到 socket fd
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
// 把 socket fd 包装成一个 LocalServerSocket 并返回
return new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error building socket from file descriptor: " + fileDesc, ex);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
这里的流程很清晰:
- 从环境遍历中获取到 socket fd
- 把 socket fd 包装成一个 LocalServerSocket 并返回
至此, ZygoteServer 的初始化过程就分析完了,
# 2.2 调用 runSelectLoop
方法进入无限循环中等待 socket 消息
runSelectLoop
会进入一个无限循环,在循环中:
- 将需要监听的 fd 加入
StructPollfd[] pollFDs
数组,这里的 fd 主要是前面初始化好的 zygete socket fd - 调用 poll io 多路复用函数,进入休眠状态,
StructPollfd[] pollFDs
数组中的 fd 有数据到来,进程从休眠中唤醒
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
// 把前面从环境变量中获取到的 fd 加入到 socketFDs 中
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
while (true) { //进入循环
fetchUsapPoolPolicyPropsWithMinInterval();
int[] usapPipeFDs = null;
StructPollfd[] pollFDs = null;
if (mUsapPoolEnabled) { //Usap 机制,这里暂时不用管
//......
} else {
// 初始化一个 StructPollfd 数组
// 看来是要用 poll io 多路复用来监听 fd
pollFDs = new StructPollfd[socketFDs.size()];
}
// 初始化 pollFDs ,核心是把 zygote fd 加入进去
int pollIndex = 0;
for (FileDescriptor socketFD : socketFDs) {
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = socketFD;
// 监听可读事件
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
}
final int usapPoolEventFDIndex = pollIndex;
if (mUsapPoolEnabled) { //Usap 机制,这里暂时不用管
//......
}
try {
// 调用 poll ,进入休眠状态
Os.poll(pollFDs, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
// ......
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 3. SystemServer 中的 AMS 向 Zygote 发送一个启动新进程的 Socket 消息
Android 中启动一个新的进程最终都会执行到 ProcessList 中的 startProcess() 方法:
// frameworks/base/services/core/java/com/android/server/am/ProcessList.java
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkSlow(startTime, "startProcess: asking zygote to start proc");
final Process.ProcessStartResult startResult;
if (hostingRecord.usesWebviewZygote()) {
// ......
} else if (hostingRecord.usesAppZygote()) {
// ......
} else {
// 走这里
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
checkSlow(startTime, "startProcess: returned from zygote!");
return startResult;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
参数中 entryPoint 的值通常是 "android.app.ActivityThread",这个就是新进程执行的第一个 Java 类 android.app.ActivityThread
.
接着会执行 Process.start
,我们跟踪一下执行流程:
// frameworks/base/core/java/android/os/Process.java
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags,
int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
/*useUsapPool=*/ true, zygoteArgs);
}
// frameworks/base/core/java/android/os/ZygoteProcess.java
public final Process.ProcessStartResult start(@NonNull final String processClass,
final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
boolean useUsapPool,
@Nullable String[] zygoteArgs) {
// TODO (chriswailes): Is there a better place to check this value?
if (fetchUsapPoolEnabledPropWithMinInterval()) {
informZygotesOfUsapPoolStatus();
}
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, useUsapPool, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
// frameworks/base/core/java/android/os/ZygoteProcess.java
private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
@Nullable final String niceName,
final int uid, final int gid,
@Nullable final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
boolean startChildZygote,
@Nullable String packageName,
boolean useUsapPool,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
argsForZygote.add("--mount-external-full");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
argsForZygote.add("--mount-external-installer");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
argsForZygote.add("--mount-external-legacy");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
if (packageName != null) {
argsForZygote.add("--package-name=" + packageName);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
Collections.addAll(argsForZygote, extraArgs);
}
synchronized(mLock) {
// The USAP pool can not be used if the application will not use the systems graphics
// driver. If that driver is requested use the Zygote application start path.
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
useUsapPool,
argsForZygote);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
Process.start
最终会调用到 startViaZygote
方法,在这个方法中:
- 将应用进程的启动参数保存到 argsForZygote 集合中
- 用 openZygoteSocketIfNeeded() 方法用来创建用于通信的 socket
- 调用 zygoteSendArgsAndGetResult 方法将应用程序进程的启动参数通过 socket 发送的 Zygote 进程
这里代码有点繁琐,这里我整理了核心的代码:
// openZygoteSocketIfNeeded 内部
// 通过 LocalSocket 建立与 Zygote 的 socket 连接
mZygoteSocketAddress = new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME,
LocalSocketAddress.Namespace.RESERVED);
final LocalSocket zygoteSessionSocket = new LocalSocket();
// 这里的参数 zygoteSocketAddress 就是上面的 mZygoteSocketAddress
zygoteSessionSocket.connect(zygoteSocketAddress);
// zygoteSendArgsAndGetResult 内部
// 将应用程序进程的启动参数通过 socket 发送的 Zygote 进程
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
zygoteWriter.write(msgStr);
zygoteWriter.flush();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
到这里,AMS 的工作就结束了。接下来 Zygote 就会收到启动新进程的数据,同时从 poll 的休眠中唤醒。
# 4. Zygote 从休眠中唤醒,从 socket 中读取数据,fork 新进程并执行新进程的 main 函数
- 当收到数据时,poll 函数从休眠中唤醒
- 如果是 zygote fd,构建一个与客户端通信的 ZygoteConnection 类型的辅助对象,同时把与客户端连接的 fd 存入到 socketFDs 中,下次循环,fd 会加入 pollFDs 中被 poll 函数监听
- 如果是与客户端连接的 fd,则调用 processOneCommand 函数读取客户端发来的数据,创建新的进程,把新进程的 main 函数包装为一个 Runnable 对象,如果是子进程就把这个 Runnable 对象返回到上一级 main 函数中,在 main 函数中就
以下是 runSelectLoop
函数这部分的具体实现:
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
try {
Os.poll(pollFDs, -1); // poll 监听 fd
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
boolean usapPoolFDRead = false;
// poll 唤醒,开始收数据,处理数据
while (--pollIndex >= 0) {
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
if (pollIndex == 0) { //第一个 zygote socket fd
// Zygote server socket
// 构建一个与客户端通信的 ZygoteConnection 类型的辅助对象
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
// 把与客户端连接的 fd 存入到 socketFDs
// 下次循环,fd 会加入 pollFDs 中被监听
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) { // 与客户端连接的 fd
// Session socket accepted from the Zygote server socket
try {
// 读取客户端发来的数据,创建新的进程,把新进程的 main 函数包装为一个 Runnable 对象
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
// TODO (chriswailes): Is this extra check necessary?
// 子进程直接返回 Runnable
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This
// shows up as a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(pollIndex);
socketFDs.remove(pollIndex);
}
}
} catch (Exception e) {
if (!mIsForkChild) {
// We're in the server so any exception here is one that has taken place
// pre-fork while processing commands or reading / writing from the
// control socket. Make a loud noise about any such exceptions so that
// we know exactly what failed and why.
Slog.e(TAG, "Exception executing zygote command: ", e);
// Make sure the socket is closed so that the other end knows
// immediately that something has gone wrong and doesn't time out
// waiting for a response.
ZygoteConnection conn = peers.remove(pollIndex);
conn.closeSocket();
socketFDs.remove(pollIndex);
} else {
// We're in the child so any exception caught here has happened post
// fork and before we execute ActivityThread.main (or any other main()
// method). Log the details of the exception and bring down the process.
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
} finally {
// Reset the child flag, in the event that the child process is a child-
// zygote. The flag will not be consulted this loop pass after the Runnable
// is returned.
mIsForkChild = false;
}
} else {
// ......
}
}
// ......
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
接着看核心的 processOneCommand 函数:
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
ZygoteArguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
// 从 socket 中读取创建新进程的参数
args = Zygote.readArgumentList(mSocketReader);
// TODO (chriswailes): Remove this and add an assert.
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
// readArgumentList returns null only when it has reached EOF with no available
// data to read. This will only happen when the remote socket has disconnected.
if (args == null) {
isEof = true;
return null;
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
// 解析处理参数
parsedArgs = new ZygoteArguments(args);
if (parsedArgs.mAbiListQuery) {
handleAbiListQuery();
return null;
}
if (parsedArgs.mPidQuery) {
handlePidQuery();
return null;
}
if (parsedArgs.mUsapPoolStatusSpecified) {
return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
}
if (parsedArgs.mPreloadDefault) {
handlePreload();
return null;
}
if (parsedArgs.mPreloadPackage != null) {
handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
return null;
}
if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
Parcel appInfoParcel = Parcel.obtain();
appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
appInfoParcel.setDataPosition(0);
ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
appInfoParcel.recycle();
if (appInfo != null) {
handlePreloadApp(appInfo);
} else {
throw new IllegalArgumentException("Failed to deserialize --preload-app");
}
return null;
}
if (parsedArgs.mApiBlacklistExemptions != null) {
return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
}
if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
|| parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
return handleHiddenApiAccessLogSampleRate(zygoteServer,
parsedArgs.mHiddenApiAccessLogSampleRate,
parsedArgs.mHiddenApiAccessStatslogSampleRate);
}
if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: "
+ "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
+ ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
}
Zygote.applyUidSecurityPolicy(parsedArgs, peer);
Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null;
if (parsedArgs.mRLimits != null) {
rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
}
int[] fdsToIgnore = null;
if (parsedArgs.mInvokeWith != null) {
try {
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
Os.fcntlInt(childPipeFd, F_SETFD, 0);
fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
} catch (ErrnoException errnoEx) {
throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
}
}
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
* in the child process before it switches from Zygote-root to
* the UID and privileges of the application being launched.
*
* In order to avoid "bad file descriptor" errors when the
* two LocalSocket objects are closed, the Posix file
* descriptors are released via a dup2() call which closes
* the socket and substitutes an open descriptor to /dev/null.
*/
int [] fdsToClose = { -1, -1 };
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
fdsToClose[0] = fd.getInt$();
}
fd = zygoteServer.getZygoteSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
}
fd = null;
// 执行 forkAndSpecialize 创建新进程
// forkAndSpecialize 是对 fork 系统调用的包装
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
try {
if (pid == 0) { // 子进程
// in child
// 设置 mIsForkChild 为true
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
// 通过反射找到启动类的 main 函数
// 并包装到 Runnable 的 run 函数中
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
总体流程就是:
- 解析出创建新进程的参数
- 执行 forkAndSpecialize 创建新进程,forkAndSpecialize 是对 fork 系统调用的包装
- 如果是子进程,调用 handleChildProc 方法,通过反射找到启动类的 main 函数并包装成 Runnable 对象返回
接着再看 handleChildProc 方法的具体实现:
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
* objects still need to be closed properly.
*/
closeSocket();
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
首先重新设置标准输入输出错误文件描述符,关闭了监听用的 socket 和从 Zygote 中继承的文件描述符。
if (parsedArgs.mNiceName != null) {
Process.setArgV0(parsedArgs.mNiceName);
}
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.mInvokeWith != null) {
WrapperInit.execApplication(parsedArgs.mInvokeWith,
parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.mRemainingArgs);
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, null /* classLoader */);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
先设置进程的名字,然后根据启动参数是否有 --runtime-init
以及 --invoke-with
来判断如何初始化。
- 启动 apk 应用都会带有 --runtime-init 参数,--invoke-with 通常为 null
- --invoke-with 不为 null 将会通过 exec 的方式启动 app_process 来执行 Java类
- 大多数情况下会调用 ZygoteInit.zygoteInit 方法
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ZygoteInit.zygoteInit 方法又调用了三个方法:RuntimeInit.commonInit()、ZygoteInit.nativeZygoteInit()、RuntimeInit.applicationInit(),最后 return 一个 Runnable 的对象给调用者。
commonInit() 用于执行一些通用配置的初始化:
- 设置 KillApplicationHandler 为默认的 UncaughtExceptionHandler
- 设置时区
- 设置 http.agent 属性,用于 HttpURLConnection
- 重置 Android 的 Log 系统
- 通过 NetworkManagementSocketTagger 设置 socket 的 tag,用于流量统计
nativeZygoteInit() 是一个 native 方法:
private static final native void nativeZygoteInit();
// frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
// gCurRuntime 是 AppRuntime 的实例
gCurRuntime->onZygoteInit();
}
2
3
4
5
6
7
8
9
这里接着会调用 AppRuntime 的 onZygoteInit() 方法:
// frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
2
3
4
5
6
7
这部分代码在 Binder 中我都介绍过了,主要用于初始化 Binder 的使用环境,这样,应用进程就可以使用 Binder 了。
接着函数会执行到 applicationInit
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 设置虚拟机的 HeapUtilization 为 0.75f
- 设置当前的 SDKVersion
- 调用 findStaticMain() 函数来查找 Java 类的 main 方法,并包装成 Runnable 的形式
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
return new MethodAndArgsCaller(m, argv);
}
static class MethodAndArgsCaller implements Runnable {
private final Method mMethod;
private final String[] mArgs;
......
public void run() {
......
mMethod.invoke(null, new Object[] { mArgs });
......
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
这里就是通过反射拿到 main 方法,然后在 Runnable 的 run 方法中去执行这个 main 方法